package cn.edu.dgut.sai;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.*;

/**
 * @author Sai
 *
 * Java EE课程示例
 *
 * curl http://localhost:8080/test/threadPoolAsync 或 在浏览器里输入网址，观察服务器的输出
 *
 * 注意servlet的线程名字与线程池中的线程的名字的区别，异步线程池与容器的http线程池。
 *
 */
@WebServlet(value = "/threadPoolAsync", asyncSupported = true)
public class ThreadPoolAsyncHelloServlet extends HttpServlet {

    // 线程池是共享资源，用volatile修饰，保证一定的“有序性”，轻量级的同步
    private volatile ExecutorService executorService;

    // servlet被加载时，实例化一个线程池。
    @Override
    public void init() throws ServletException {
        super.init();
        // 实例化一个线程池，400线程数。
        executorService = Executors.newFixedThreadPool(400);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) {

        System.out.println("使用线程池的异步Servlet执行开始...");
        long start = System.currentTimeMillis();
        System.out.println("进入Servlet线程--" + Thread.currentThread().getName());

        AsyncContext asyncContext = request.startAsync();

        // 向线程池发送一个任务，任务在lambda表达式中定义。
        executorService.submit(() -> {

            new RunningProcessThread().run();

            try {
                response.setContentType("text/html;charset=UTF-8");
                asyncContext.getResponse().getWriter().println("使用线程池的异步Servlet示例，Hello World!");
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 线程执行完成，响应客户端
            asyncContext.complete();

            System.out.println("退出异步线程--" + Thread.currentThread().getName());

        });

        long end = System.currentTimeMillis();
        System.out.println("使用线程池的异步Servlet执行完成，耗时：" + (end - start) + "毫秒");
        System.out.println("退出Servlet线程--" + Thread.currentThread().getName());
    }

    // servlet结束时，清除线程池。
    @SuppressWarnings("Duplicates")
    @Override
    public void destroy() {

        super.destroy();
        executorService.shutdown();
        boolean successfulTerminated = false;
        try {
            successfulTerminated = executorService.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!successfulTerminated) {
            executorService.shutdownNow();
        }
        executorService = null;
    }

}